package org.smartboot.flow.manager.report;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.smartboot.flow.core.manager.EngineModel;
import org.smartboot.flow.core.util.AssertUtil;
import org.smartboot.http.client.HttpClient;
import org.smartboot.http.client.HttpPost;
import org.smartboot.http.common.enums.HeaderNameEnum;

import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * @author qinluo
 * @date 2022/11/23 20:47
 * @since 1.0.0
 */
public class HttpReporter extends AbstractReporter {

    private static final Logger LOGGER = LoggerFactory.getLogger(HttpReporter.class);

    private String url;
    private long timeout;
    private URL parsedUrl;
    private Map<String, String> headers;

    @Override
    public void start() {
        try {
            this.parsedUrl = new URL(url);
        } catch (Exception e) {
            throw new IllegalStateException("invalid url " + url, e);
        }

        super.start();
    }

    @Override
    public void doExport(EngineModel model) {
        AssertUtil.notNull(parsedUrl, "url is invalid.");

        String path = parsedUrl.getPath();
        if (parsedUrl.getQuery() != null) {
            path = path + "?" + parsedUrl.getQuery();
        }

        HttpClient httpClient = new HttpClient(parsedUrl.getHost(), parsedUrl.getPort());
        httpClient.timeout((int)timeout);
        httpClient.connect();
        HttpPost post = httpClient.post(path);

        if (headers != null) {
            headers.forEach(post::addHeader);
        }

        HttpReportModel reportModel = new HttpReportModel();
        reportModel.setAddress(HostUtils.getHostIp());
        reportModel.setHost(HostUtils.getHostName());
        reportModel.setTimestamp(System.currentTimeMillis());
        reportModel.setData(model);

        String json = JSON.toJSONString(reportModel, SerializerFeature.WriteEnumUsingToString);
        byte[] bytes = json.getBytes(StandardCharsets.UTF_8);

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("report engine data, engine = {}, data = {}", model.getIdentifier(), json);
        }

        post.addHeader(HeaderNameEnum.CONTENT_TYPE.getName(), "application/json;charset=UTF-8");
        post.addHeader(HeaderNameEnum.CONTENT_LENGTH.getName(), String.valueOf(bytes.length));

        // Use body stream write.
        post.bodyStream().write(bytes, 0, bytes.length);
        post.bodyStream().flush();
        post.onSuccess(httpResponse -> LOGGER.info("send statistic success, engine: {}", model.getIdentifier()))
                .onFailure(throwable -> LOGGER.info("send statistic failed, engine: {}", model.getIdentifier(), throwable));

        post.send();
    }

    public Map<String, String> getHeaders() {
        return headers;
    }

    public void setHeaders(Map<String, String> headers) {
        this.headers = headers;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public long getTimeout() {
        return timeout;
    }

    public void setTimeout(long timeout) {
        this.timeout = timeout;
    }
}
